import { DataProcess } from './dataProcess'
import { ParticleSystem } from './particleSystem'
import { Util } from './util'

class Wind3D {
  constructor(panel, mode, viewer) {
    this.viewer = viewer
    this.scene = this.viewer.scene
    this.camera = this.viewer.camera

    this.panel = panel

    this.moveStartFunc = this.moveStartFunc.bind(this)
    this.moveEndFunc = this.moveEndFunc.bind(this)
    this.windowResizeFunc = this.windowResizeFunc.bind(this)
    this.preRenderFunc = this.preRenderFunc.bind(this)
    this.optionsChangedFunc = this.optionsChangedFunc.bind(this)

    this.viewerParameters = {
      lonRange: new Cesium.Cartesian2(),
      latRange: new Cesium.Cartesian2(),
      pixelSize: 0.0
    }
    // use a smaller earth radius to make sure distance to camera > 0
    this.globeBoundingSphere = new Cesium.BoundingSphere(Cesium.Cartesian3.ZERO, 0.99 * 6378137.0)
    this.updateViewerParameters()
    this.viewerParameters.pixelSize = 133
    DataProcess.loadData().then(data => {
      this.particleSystem = new ParticleSystem(this.scene.context, data, this.panel.getUserInput(), this.viewerParameters)
      this.addPrimitives()

      // this.setupEventListeners()
    })
  }

  addPrimitives() {
    // the order of primitives.add() should respect the dependency of primitives
    this.getWind = this.scene.primitives.add(this.particleSystem.particlesComputing.primitives.getWind)
    this.updateSpeed = this.scene.primitives.add(this.particleSystem.particlesComputing.primitives.updateSpeed)
    this.updatePosition = this.scene.primitives.add(this.particleSystem.particlesComputing.primitives.updatePosition)
    this.postProcessingPosition = this.scene.primitives.add(this.particleSystem.particlesComputing.primitives.postProcessingPosition)
    this.postProcessingSpeed = this.scene.primitives.add(this.particleSystem.particlesComputing.primitives.postProcessingSpeed)

    this.segments = this.scene.primitives.add(this.particleSystem.particlesRendering.primitives.segments)
    this.trails = this.scene.primitives.add(this.particleSystem.particlesRendering.primitives.trails)
    this.screen = this.scene.primitives.add(this.particleSystem.particlesRendering.primitives.screen)
    // this.setupEventListeners()
    this.hidePrimitives()
  }
  hidePrimitives() {
    for (const item of this.scene.primitives._primitives) {
      if (item.commandType === 'Compute' || item.commandType === 'Draw') {
        item.show = false
      }
    }
    this.removeEventListeners()
  }
  showPrimitives() {
    // for (const item of this.scene.primitives._primitives) {
    //   if (item.commandType === 'Compute' || item.commandType === 'Draw') {
    //     item.show = true
    //   }
    // }
    this.setupEventListeners()
    this.moveStartFunc()
    this.moveEndFunc()
  }
  removePrimitives() {
    this.scene.primitives.remove(this.getWind)
    this.scene.primitives.remove(this.updateSpeed)
    this.scene.primitives.remove(this.updatePosition)
    this.scene.primitives.remove(this.postProcessingPosition)
    this.scene.primitives.remove(this.postProcessingSpeed)

    this.scene.primitives.remove(this.segments)
    this.scene.primitives.remove(this.trails)
    this.scene.primitives.remove(this.screen)
    this.removeEventListeners()
  }

  updateViewerParameters() {
    const viewRectangle = this.camera.computeViewRectangle(this.scene.globe.ellipsoid)
    const lonLatRange = Util.viewRectangleToLonLatRange(viewRectangle)
    this.viewerParameters.lonRange.x = lonLatRange.lon.min
    this.viewerParameters.lonRange.y = lonLatRange.lon.max
    this.viewerParameters.latRange.x = lonLatRange.lat.min
    this.viewerParameters.latRange.y = lonLatRange.lat.max

    const pixelSize = this.camera.getPixelSize(this.globeBoundingSphere, this.scene.drawingBufferWidth, this.scene.drawingBufferHeight)

    if (pixelSize > 0) {
      this.viewerParameters.pixelSize = pixelSize
    }
  }
  moveStartFunc() {
    for (const item of this.scene.primitives._primitives) {
      if (item.commandType === 'Compute' || item.commandType === 'Draw') {
        item.show = false
      }
    }
  }
  moveEndFunc() {
    this.updateViewerParameters()
    this.particleSystem.applyViewerParameters(this.viewerParameters)
    for (const item of this.scene.primitives._primitives) {
      if (item.commandType === 'Compute' || item.commandType === 'Draw') {
        item.show = true
      }
    }
  }
  windowResizeFunc() {
    this.resized = true
    for (const item of this.scene.primitives._primitives) {
      if (item.commandType === 'Compute' || item.commandType === 'Draw') {
        item.show = false
      }
    }
    this.scene.primitives.removeAll()
  }
  preRenderFunc() {
    if (this.resized) {
      this.particleSystem.canvasResize(this.scene.context)
      this.resized = false
      this.addPrimitives()
      for (const item of this.scene.primitives._primitives) {
        if (item.commandType === 'Compute' || item.commandType === 'Draw') {
          item.show = true
        }
      }
    }
  }
  optionsChangedFunc() {
    this.particleSystem.applyUserInput(this.panel.getUserInput())
  }
  setupEventListeners() {
    // this.scene.primitives.show = true
    this.camera.moveStart.addEventListener(this.moveStartFunc)

    this.camera.moveEnd.addEventListener(this.moveEndFunc)
    this.resized = false
    window.addEventListener('resize', this.windowResizeFunc)

    this.scene.preRender.addEventListener(this.preRenderFunc)

    window.addEventListener('particleSystemOptionsChanged', this.optionsChangedFunc)
  }
  removeEventListeners() {
    // this.scene.primitives.show = false
    this.camera.moveStart.removeEventListener(this.moveStartFunc)

    this.camera.moveEnd.removeEventListener(this.moveEndFunc)
    this.resized = false
    window.removeEventListener('resize', this.windowResizeFunc)

    this.scene.preRender.removeEventListener(this.preRenderFunc)

    window.removeEventListener('particleSystemOptionsChanged', this.optionsChangedFunc)
  }
}
export { Wind3D }
